<?
/**	TimeLine_Abstract Class
*	Date:	2012-04-01
*	Author:	terrywu,merlin
*   Func:   get, get_status, get_content, add, del, add_follow, del_follow, feed
*/

abstract class TimeLine_Abstract{	// class start

    protected $config = array(
                            'mode'      =>  'push',		// push or mixed
                            'shardsize' =>  2000,		// sharding size
                            'grouping'  =>  true,		// true: 同一類型事件grouping, false:每次都新增
                            'feedsize'  =>  100,			// 每N個用戶一組feed
							'db'        =>  'timeline'	// db tag
    );

	/* get feed users */
	abstract function get_receiver($mid, $type, $content);

	
	/* init */
	public final function __construct($config=array()){
        $this->config = is_array($config)? array_merge($this->config, $config) : $this->config;
	}


    /** 獲取Timeline列表
	* @param  int		$mid		用戶id
	* @param  String	$type		動態類型
	* @param  int		$direction	0:all 1:自己 2:自己關注的
	* @param  Array		$param		limit
	* @param  datetime	$updatetime 最後更新時間
	* @return Array
	*/
    public function get($mid, $type='', $direction=1, $param=array(), $updatetime=''){
		$mid = intval($mid);
		if(empty($mid)){
			return array();
		}
		$type = strval($type);
		$direction = intval($direction);
		!in_array($direction, array(0, 1, 2)) && $direction = 1;
		$limit = isset($param['limit']) ? intval($param['limit']) : 20;
		$limit <= 0 && $limit = 20;
		empty($updatetime) && $updatetime = date('Y-m-d H:i:s');
		$where = array('mid' => $mid, 'status' => 1, 'addtime' => array('$lt' => $updatetime));
		!empty($type) && $where['type'] = $type;
		!empty($direction) && $where['direction'] = $direction;
		$timeline_user_table = 'timeline_user_' . $this->get_table($mid);
		$query_param = array(
			'where' => $where,
			'limit' => $limit,
			'order' => array('addtime' => -1)
		);
    	$data = db_query_hash($timeline_user_table, $query_param, $this->config['db']);
		return $data['result'];
    }


	/** 獲取TimeLine統計
	* @param  int		$mid		用戶id
	* @param  Array		$types		動態類型集合
	* @param  int		$direction	0:all 1:自己 2:自己關注的
	* @param  datetime	$updatetime 最後更新時間
	* @return Array
	*/
	public function get_status($mid, array $types, $direction=1, $updatetime=''){

		$mid = intval($mid);
		if(empty($mid) || empty($types)){
			return array();
		}
		$types = array_map('strval', $types);
		$all_key = array_search('all', $types);
		if($all_key !== false && $all_key !== null){
			unset($types[$all_key]);
			$all_type = 'all';
		}else{
			$all_type = '';
		}
		$direction = intval($direction);
		$updatetime = strval($updatetime);
		!in_array($direction, array(0, 1, 2)) && $direction = 1;
		$where = array('mid' => $mid, 'status' => 1, 'type' => array('$in' => $types));
		!empty($direction) && $where['direction'] = $direction;
		$collection = db_handle('selectCollection', array('timeline_user_' . $this->get_table($mid)), $this->config['db']);
		$g = $collection->group(
			array('type' => 1), 
			array('count' => 0, 'new_count' => 0), 
			"function(obj, prev){prev.count++;if(obj.addtime >= '" . $updatetime . "'){prev.new_count++;}}",
			$where
		);
		$status = array();
		if(!empty($g['retval'])){
			foreach($g['retval'] as $retval){
				$status[$retval['type']] = array(
					'count' => $retval['count'],
					'new_count' => $retval['new_count']
				);
			}
		}else{
			foreach($types as $type){
				$status[$type] = array(
					'count' => 0,
					'new_count' => 0
				);
			}
		}
		if($all_type == 'all'){
			$where = array('mid' => $mid, 'status' => 1);
			!empty($direction) && $where['direction'] = $direction;
			$status['all'] = array(
				'count' => $collection->find($where)->count(),
				'new_count' => $collection->find(array_merge($where, array('addtime' => array('$gt' => $updatetime))))->count()
			);
		}

		return $status;
		
	}
	

    /** 新增Timeline
	* @param  int		$mid		用戶id
	* @param  String	$type		動態類型
	* @param  String	$from		來源
	* @param  String	$key		唯一key
	* @param  Array		$content	動態內容
	* @param  boolean	$group		是否group
	* @return boolean
	*/
    public function add($mid, $type, $from, $key, $content, $group=null){
		
		$mid = intval($mid);
		if(empty($mid)){
			return false;
		}
		$type = strval($type);
		if(empty($type)){
			return false;
		}
		$from = strval($from);
		if(empty($from)){
			return false;
		}
		$key = strval($key);
		if(empty($key)){
			return false;
		}
		if(empty($content)){
			return false;
		}
		$group = !is_null($group) ? $group : $this->config['grouping'];
		
		$addtime = date('Y-m-d H:i:s');
		$table_date = date('Ym');
		$timeline_home_table = 'timeline_home_' . $table_date;
		//insert into home_timeline
		$timeline_home_id = db_add($timeline_home_table, array(
			'mid' => $mid,
			'type' => $type,
			'from' => $from,
			'key' => $key,
			'content' => $content,
			'addtime' => $addtime,
			'status'  => 1
		), $this->config['db']);
		if(empty($timeline_home_id)){
			return false;
		}
		
		//insert into own timeline_user
		$content_id = $timeline_home_table . '|' . $timeline_home_id;
		$own_timeline_table = 'timeline_user_' . $this->get_table($mid);
		if($group){
			db_del($own_timeline_table, array(
				'mid' => $mid,
				'key' => $key
			), $this->config['db']);
		}
		$own_timeline_data = array(
			'mid' => $mid,
			'type' => $type,
			'from' => $from,
			'key' => $key,
			'direction' => 1,
			'content_id' => $content_id,
			'addtime' => $addtime,
			'status' => 1
		);
		db_add($own_timeline_table, $own_timeline_data, $this->config['db']);
		
		//update own timeline_homestat
		$homestat = db_query_one('timeline_homestat_' . $table_date, array(
			'field' => 'num',
			'where' => array('mid' => $mid)
		), $this->config['db']);
		if(empty($homestat['result'])){
			db_add('timeline_homestat_' . $table_date, array(
				'mid' => $mid,
				'num' => 1, 
				'lastcontent_id' => $content_id
			), $this->config['db']);
		}else{
			db_update('timeline_homestat_' . $table_date, array(
				'num' => $homestat['result']['num']+1, 
				'lastcontent_id' => $content_id
			), array(
				'mid' => $mid
			), $this->config['db']);
		}

		//push to receiver
		$timeline_user_data = array(
			'type' => $type,
			'from' => $from,
			'key' => $key,
			'direction' => 2,
			'content_id' => $content_id,
			'addtime' => $addtime,
			'status' => 1
		);

		$receiver_mids = array_chunk($this->get_receiver($mid, $type, $content), $this->config['feedsize']);
    	$gmc = getLibClass('GMC');
		foreach($receiver_mids as $mids){
			$gmc->job_do('timeline_feed', array(
				'receiver_mids' => $mids,
				'timeline_user_data' => $timeline_user_data,
				'group' => $group
			));
		}

		return true;

    }


	/** 刪除動態內容
	* @param  int	$mid	用戶id
	* @param  Array	$keys	key集合
	* @return Array
	*/
	public function del($mid, array $keys){
		$mid = intval($mid);
		if(empty($mid)){
			return array();
		}
		if(empty($keys)){
			return array();
		}
		$keys = array_map('strval', $keys);
		$data = db_query_hash('timeline_user_' . $this->get_table($mid), array(
			'field' => 'content_id',
			'where' => array('mid'  => $mid, 'direction' => 1, 'key' => array('$in' => $keys), 'status' => 1)
		), $this->config['db']);
		$content_ids = array();
		if(!empty($data['result'])){
			//删除timeline_home
			foreach($data['result'] as $result){
				list($timeline_home_table, $id) = explode('|', $result['content_id']);
				$id = intval($id);
				db_update($timeline_home_table, array('status' => 0), array(
					'id'  => $id
				), $this->config['db']);
				$content_ids[] = $result['content_id'];
			}
			//删除timeline_user记录 
			$collections = db_handle('listCollections', array(), $this->config['db']);
			foreach($collections as $collection){
				if(strpos($collection->getName(), 'timeline_user_') !== false){
					$collection->update(
						array(
							'content_id' => array('$in' => $content_ids)
						), 
						array(
							'$set' => array('status' => 0)
						),
						array('safe' => true, 'multiple' => true)
					);
				}
			}	
		}
		return $content_ids;
	}


	/** 加關注，將關注用戶的timeline寫入
	* @param  int		$mid	用戶id
	* @param  String	$from	來源
	* @return boolean
	*/
	public function add_follow($mid, $from, $group=null){
		$mid = intval($mid);
		if(empty($mid)){
			return false;
		}
		if(empty($from)){
			return false;
		}
		if($mid == $from){
			return false;
		}
		$group = !is_null($group) ? $group : $this->config['grouping'];
		$timeline_user_table = 'timeline_user_' . $this->get_table($mid);
		$data = db_query_one($timeline_user_table, array(
			'where' => array('mid'  => $mid, 'from' => strval($from), 'status' => 1),
			'order' => array('id' => -1)
		), $this->config['db']);
		$last_timeline_id = isset($data['result']['id']) ? $data['result']['id'] : 0; 
		//取最新50条记录
    	$data = db_query_hash('timeline_user_' . $this->get_table($from), array(
			'where' => array('mid'  => intval($from), 'direction' => 1, 'id' => array('$gt' => $last_timeline_id), 'status' => 1),
			'limit' => 50,
			'order' => array('id' => -1)
		), $this->config['db']);
		$keys = array();
		foreach($data['result'] as $timeline){
			$keys[] = $timeline['key'];
			db_add($timeline_user_table, array(
				'mid' => $mid,
				'type' => $timeline['type'],
				'from' => strval($from),
				'key' => $timeline['key'],
				'direction' => 2,
				'content_id' => $timeline['content_id'],
				'addtime' => $timeline['addtime'],
				'status' => 1
			), $this->config['db']);
		}
		if(!empty($keys) && $group){
			db_update($timeline_user_table, array('status' => 0), array(
				'mid'  => $mid,
				'from' => strval($from),
				'status' => 2,
				'key'  => array('$in' => $keys)
			), $this->config['db']);
		}
		
		db_update($timeline_user_table, array('status' => 1), array(
			'mid'  => $mid,
			'from' => strval($from),
			'status'     => 2
		), $this->config['db']);
		
		return true;
	}


	/** 取消關注，將之前關注的TimeLine刪除
	* @param  int		$mid	用戶id
	* @param  String	$from	來源
	* @return boolean
	*/
	public function del_follow($mid, $from){
		$mid = intval($mid);
		if(empty($mid)){
			return false;
		}
		$from = strval($from);
		if(empty($from)){
			return false;
		}
		if($mid == $from){
			return false;
		}
		$timeline_user_table = 'timeline_user_' . $this->get_table($mid);
		db_update($timeline_user_table, array('status' => 2), array(
			'mid'  => $mid,
			'from' => $from
		), $this->config['db']);
		return true;
	}


	/** 獲取動態內容
	* @param  String $content_id 動態id
	* @return Json
	*/
	public function get_content($content_id){
		if(empty($content_id)){
			return '';
		}
		list($timeline_home_table, $id) = explode('|', $content_id);
		$id = intval($id);
		if(empty($timeline_home_table) || empty($id)){
			return '';
		}
		$data = db_query_one($timeline_home_table, array('field' => 'content', 'where' => array('id' => $id)), $this->config['db']);
		$content = isset($data['result']['content']) ? $data['result']['content'] : '';
		return $content;
	}


    /** 獲取用戶分片表名
    * @param  int    $mid 用戶id
    * @return String
    */
    protected function get_table($mid){
        $shardsize = $this->config['shardsize'];
        return str_pad(floor($mid/$shardsize), 4, '0', STR_PAD_LEFT);
    }

}	// class end
?>
